/*
 * SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
 *
 * SPDX-License-Identifier: MulanPSL-2.0
 */
#![allow(
    dead_code,
    mutable_transmutes,
    non_camel_case_types,
    non_snake_case,
    non_upper_case_globals,
    unused_assignments,
    unused_mut,
    clippy::never_loop
)]

use crate::common::*;

extern "C" {
    fn snprintf(
        _: *mut libc::c_char,
        _: libc::c_ulong,
        _: *const libc::c_char,
        _: ...
    ) -> libc::c_int;
    fn getresuid(__ruid: *mut __uid_t, __euid: *mut __uid_t, __suid: *mut __uid_t) -> libc::c_int;
    fn getresgid(__rgid: *mut __gid_t, __egid: *mut __gid_t, __sgid: *mut __gid_t) -> libc::c_int;
    fn setresuid(__ruid: __uid_t, __euid: __uid_t, __suid: __uid_t) -> libc::c_int;
    fn setresgid(__rgid: __gid_t, __egid: __gid_t, __sgid: __gid_t) -> libc::c_int;
    fn __errno_location() -> *mut libc::c_int;
    fn sudo_warn_nodebug_v1(fmt: *const libc::c_char, _: ...);
    fn sudo_warnx_nodebug_v1(fmt: *const libc::c_char, _: ...);
    static mut sudo_defs_table: [sudo_defs_types; 0];
    fn runas_getgroups() -> *mut gid_list;
    fn sudo_setgroups_v1(ngids: libc::c_int, gids: *const gid_t) -> libc::c_int;
    fn sudo_debug_printf2_v1(
        func: *const libc::c_char,
        file: *const libc::c_char,
        line: libc::c_int,
        level: libc::c_int,
        fmt: *const libc::c_char,
        _: ...
    );
    static mut sudoers_subsystem_ids: [libc::c_uint; 0];
    fn sudo_gidlist_delref(_: *mut gid_list);
    static mut iolog_uid: uid_t;
    static mut iolog_gid: gid_t;
    fn sudo_gidlist_addref(_: *mut gid_list);
    static mut timestamp_uid: uid_t;
    static mut sudoers_uid: uid_t;
    static mut sudoers_mode: mode_t;
    static mut sudoers_gid: gid_t;
    static mut sudo_user: sudo_user;
}

pub const PERM_STACK_MAX: libc::c_int = 16;
pub const PERM_INITIAL: libc::c_int = 0x00;
pub const PERM_ROOT: libc::c_int = 0x01;
pub const PERM_USER: libc::c_int = 0x02;
pub const PERM_FULL_USER: libc::c_int = 0x03;
pub const PERM_SUDOERS: libc::c_int = 0x04;
pub const PERM_RUNAS: libc::c_int = 0x05;
pub const PERM_TIMESTAMP: libc::c_int = 0x06;
pub const PERM_IOLOG: libc::c_int = 0x07;
pub const ROOT_UID: libc::c_int = 0;
pub const ROOT_GID: libc::c_int = 0;

#[derive(Copy, Clone)]
#[repr(C)]
pub struct perm_state {
    pub ruid: uid_t,
    pub euid: uid_t,
    pub suid: uid_t,
    pub rgid: gid_t,
    pub egid: gid_t,
    pub sgid: gid_t,
    pub gidlist: *mut gid_list,
}
static mut perm_stack: [perm_state; 16] = [perm_state {
    ruid: 0,
    euid: 0,
    suid: 0,
    rgid: 0,
    egid: 0,
    sgid: 0,
    gidlist: 0 as *const gid_list as *mut gid_list,
}; 16];
static mut perm_stack_depth: libc::c_int = 0 as libc::c_int;

#[macro_export]
macro_rules! UID_CHANGED {
    ($state:expr, $ostate:expr) => {
        ((*$state).ruid != (*$ostate).ruid
            || (*$state).euid != (*$ostate).euid
            || (*$state).suid != (*$ostate).suid)
    };
}
#[macro_export]
macro_rules! GID_CHANGED {
    ($state:expr, $ostate:expr) => {
        ((*$state).rgid != (*$ostate).rgid
            || (*$state).egid != (*$ostate).egid
            || (*$state).sgid != (*$ostate).sgid)
    };
}

#[macro_export]
macro_rules! ID {
    ($x:expr, $ox:expr) => {
        (if $x == $ox {
            -(1 as libc::c_int) as uid_t
        } else {
            $x
        })
    };
}

#[macro_export]
macro_rules! OID {
    ($x:expr, $ox:expr) => {
        (if $ox == $x {
            -(1 as libc::c_int) as uid_t
        } else {
            $ox
        })
    };
}

#[no_mangle]
pub unsafe extern "C" fn rewind_perms() -> bool {
    debug_decl!(SUDOERS_DEBUG_PERMS!());

    if perm_stack_depth != 0 as libc::c_int {
        while perm_stack_depth > 1 as libc::c_int {
            if !restore_perms() {
                debug_return_bool!(false);
            }
        }
        sudo_gidlist_delref(perm_stack[0 as libc::c_int as usize].gidlist);
    }

    debug_return_bool!(true);
}

/*
 * Set real and effective and saved uids and gids based on perm.
 * We always retain a saved uid of 0 unless we are headed for an exec().
 * We only flip the effective gid since it only changes for PERM_SUDOERS.
 * This version of set_perms() works fine with the "stay_setuid" option.
 */
#[no_mangle]
pub fn set_perms(mut perm: libc::c_int) -> bool {
    let mut state: *mut perm_state = std::ptr::null_mut::<perm_state>();
    let mut ostate: *mut perm_state = std::ptr::null_mut::<perm_state>();
    let mut errbuf: [libc::c_char; 1024] = [0; 1024];
    let mut errstr: *const libc::c_char = errbuf.as_mut_ptr();
    unsafe {
        debug_decl!(SUDOERS_DEBUG_PERMS!());

        'bad: loop {
            if perm_stack_depth == PERM_STACK_MAX {
                errstr = b"perm stack overflow\0" as *const u8 as *const libc::c_char;
                *__errno_location() = EINVAL;
                break 'bad;
            }

            state =
                &mut *perm_stack.as_mut_ptr().offset(perm_stack_depth as isize) as *mut perm_state;
            if perm != PERM_INITIAL {
                if perm_stack_depth == 0 {
                    errstr = b"perm stack underflow\0" as *const u8 as *const libc::c_char;
                    *__errno_location() = EINVAL;
                    break 'bad;
                }
                ostate = &mut *perm_stack
                    .as_mut_ptr()
                    .offset((perm_stack_depth - 1 as libc::c_int) as isize)
                    as *mut perm_state;
            }

            match perm {
                PERM_INITIAL => {
                    /* Stash initial state */
                    if getresuid(&mut (*state).ruid, &mut (*state).euid, &mut (*state).suid) != 0 {
                        errstr = b"PERM_INITIAL: getresuid\0" as *const u8 as *const libc::c_char;
                        break 'bad;
                    }
                    if getresgid(&mut (*state).rgid, &mut (*state).egid, &mut (*state).sgid) != 0 {
                        errstr = b"PERM_INITIAL: getresgid\0" as *const u8 as *const libc::c_char;
                        break 'bad;
                    }

                    (*state).gidlist = sudo_user.gid_list;
                    sudo_gidlist_addref((*state).gidlist);
                    sudo_debug_printf!(
                        SUDO_DEBUG_INFO,
                        b"%s: PERM_INITIAL: \0" as *const u8 as *const libc::c_char,
                        b"ruid: %d, euid: %d, suid: %d, rgid: %d, egid: %d, sgid: %d\0" as *const u8
                            as *const libc::c_char,
                        get_function_name!(),
                        (*state).ruid as libc::c_int,
                        (*state).euid as libc::c_int,
                        (*state).suid as libc::c_int,
                        (*state).rgid as libc::c_int,
                        (*state).egid as libc::c_int,
                        (*state).sgid as libc::c_int
                    );
                }
                PERM_ROOT => {
                    (*state).ruid = ROOT_UID as uid_t;
                    (*state).euid = ROOT_UID as uid_t;
                    (*state).suid = ROOT_UID as uid_t;
                    sudo_debug_printf!(
                        SUDO_DEBUG_INFO,
                        b"%s: PERM_ROOT: uid: \0" as *const u8 as *const libc::c_char,
                        b"[%d, %d, %d] -> [%d, %d, %d]\0" as *const u8 as *const libc::c_char,
                        get_function_name!(),
                        (*ostate).ruid as libc::c_int,
                        (*ostate).euid as libc::c_int,
                        (*ostate).suid as libc::c_int,
                        (*state).ruid as libc::c_int,
                        (*state).euid as libc::c_int,
                        (*state).suid as libc::c_int
                    );
                    if UID_CHANGED!(state, ostate)
                        && setresuid(
                            ID!((*state).ruid, (*ostate).ruid),
                            ID!((*state).euid, (*ostate).euid),
                            ID!((*state).suid, (*ostate).suid),
                        ) != 0
                    {
                        snprintf(
                            errbuf.as_mut_ptr(),
                            ::core::mem::size_of::<[libc::c_char; 1024]>() as libc::c_ulong,
                            b"PERM_ROOT: setresuid(%d, %d, %d)\0" as *const u8
                                as *const libc::c_char,
                            ID!((*state).ruid, (*ostate).ruid),
                            ID!((*state).euid, (*ostate).euid),
                            ID!((*state).suid, (*ostate).suid),
                        );
                        break 'bad;
                    }
                    (*state).rgid = (*ostate).rgid;
                    (*state).egid = ROOT_GID as gid_t;
                    (*state).sgid = (*ostate).sgid;
                    sudo_debug_printf!(
                        SUDO_DEBUG_INFO,
                        b"%s: PERM_ROOT: gid: \0" as *const u8 as *const libc::c_char,
                        b"[%d, %d, %d] -> [%d, %d, %d]\0" as *const u8 as *const libc::c_char,
                        get_function_name!(),
                        (*ostate).rgid as libc::c_int,
                        (*ostate).egid as libc::c_int,
                        (*ostate).sgid as libc::c_int,
                        (*state).rgid as libc::c_int,
                        (*state).egid as libc::c_int,
                        (*state).sgid as libc::c_int
                    );
                    if GID_CHANGED!(state, ostate)
                        && setresgid(
                            ID!((*state).rgid, (*ostate).rgid),
                            ID!((*state).egid, (*ostate).egid),
                            ID!((*state).sgid, (*ostate).sgid),
                        ) != 0
                    {
                        errstr =
                            b"unable to change to root gid\0" as *const u8 as *const libc::c_char;
                        break 'bad;
                    }
                    (*state).gidlist = (*ostate).gidlist;
                    sudo_gidlist_addref((*state).gidlist);
                }
                PERM_USER => {
                    (*state).rgid = (*ostate).rgid;
                    (*state).egid = sudo_user.gid;
                    (*state).sgid = (*ostate).sgid;
                    sudo_debug_printf!(
                        SUDO_DEBUG_INFO,
                        b"%s: PERM_USER: gid: \0" as *const u8 as *const libc::c_char,
                        b"[%d, %d, %d] -> [%d, %d, %d]\0" as *const u8 as *const libc::c_char,
                        get_function_name!(),
                        (*ostate).rgid as libc::c_int,
                        (*ostate).egid as libc::c_int,
                        (*ostate).sgid as libc::c_int,
                        (*state).rgid as libc::c_int,
                        (*state).egid as libc::c_int,
                        (*state).sgid as libc::c_int
                    );
                    if GID_CHANGED!(state, ostate)
                        && setresgid(
                            ID!((*state).rgid, (*ostate).rgid),
                            ID!((*state).egid, (*ostate).egid),
                            ID!((*state).sgid, (*ostate).sgid),
                        ) != 0
                    {
                        snprintf(
                            errbuf.as_mut_ptr(),
                            ::core::mem::size_of::<[libc::c_char; 1024]>() as libc::c_ulong,
                            b"PERM_USER: setresgid(%d, %d, %d)\0" as *const u8
                                as *const libc::c_char,
                            ID!((*state).rgid, (*ostate).rgid),
                            ID!((*state).egid, (*ostate).egid),
                            ID!((*state).sgid, (*ostate).sgid),
                        );
                        break 'bad;
                    }
                    (*state).gidlist = sudo_user.gid_list;
                    sudo_gidlist_addref((*state).gidlist);
                    if (*state).gidlist != (*ostate).gidlist
                        && sudo_setgroups_v1((*(*state).gidlist).ngids, (*(*state).gidlist).gids)
                            != 0
                    {
                        errstr = b"PERM_USER: setgroups\0" as *const u8 as *const libc::c_char;
                        break 'bad;
                    }

                    /*if (*state).gidlist != (*ostate).gidlist {
                        if sudo_setgroups_v1((*(*state).gidlist).ngids, (*(*state).gidlist).gids)
                            != 0
                        {
                            errstr = b"PERM_USER: setgroups\0" as *const u8 as *const libc::c_char;
                            break 'bad;
                        }
                    }*/
                    (*state).ruid = sudo_user.uid;
                    (*state).euid = sudo_user.uid;
                    (*state).suid = ROOT_UID as uid_t;
                    sudo_debug_printf!(
                        SUDO_DEBUG_INFO,
                        b"%s: PERM_USER: uid: \0" as *const u8 as *const libc::c_char,
                        b"[%d, %d, %d] -> [%d, %d, %d]\0" as *const u8 as *const libc::c_char,
                        get_function_name!(),
                        (*ostate).ruid as libc::c_int,
                        (*ostate).euid as libc::c_int,
                        (*ostate).suid as libc::c_int,
                        (*state).ruid as libc::c_int,
                        (*state).euid as libc::c_int,
                        (*state).suid as libc::c_int
                    );
                    if UID_CHANGED!(state, ostate)
                        && setresuid(
                            ID!((*state).ruid, (*ostate).ruid),
                            ID!((*state).euid, (*ostate).euid),
                            ID!((*state).suid, (*ostate).suid),
                        ) != 0
                    {
                        snprintf(
                            errbuf.as_mut_ptr(),
                            ::core::mem::size_of::<[libc::c_char; 1024]>() as libc::c_ulong,
                            b"PERM_ROOT: setresuid(%d, %d, %d)\0" as *const u8
                                as *const libc::c_char,
                            ID!((*state).ruid, (*ostate).ruid),
                            ID!((*state).euid, (*ostate).euid),
                            ID!((*state).suid, (*ostate).suid),
                        );
                        break 'bad;
                    }
                }
                PERM_FULL_USER => {
                    /* headed for exec() */
                    (*state).rgid = sudo_user.gid;
                    (*state).egid = sudo_user.gid;
                    (*state).sgid = sudo_user.gid;
                    sudo_debug_printf!(
                        SUDO_DEBUG_INFO,
                        b"%s: PERM_FULL_USER: gid: \0" as *const u8 as *const libc::c_char,
                        b"[%d, %d, %d] -> [%d, %d, %d]\0" as *const u8 as *const libc::c_char,
                        get_function_name!(),
                        (*ostate).rgid as libc::c_int,
                        (*ostate).egid as libc::c_int,
                        (*ostate).sgid as libc::c_int,
                        (*state).rgid as libc::c_int,
                        (*state).egid as libc::c_int,
                        (*state).sgid as libc::c_int
                    );
                    if GID_CHANGED!(state, ostate)
                        && setresgid(
                            ID!((*state).rgid, (*ostate).rgid),
                            ID!((*state).egid, (*ostate).egid),
                            ID!((*state).sgid, (*ostate).sgid),
                        ) != 0
                    {
                        snprintf(
                            errbuf.as_mut_ptr(),
                            ::core::mem::size_of::<[libc::c_char; 1024]>() as libc::c_ulong,
                            b"PERM_FULL_USER: setresgid(%d, %d, %d)\0" as *const u8
                                as *const libc::c_char,
                            ID!((*state).rgid, (*ostate).rgid),
                            ID!((*state).egid, (*ostate).egid),
                            ID!((*state).sgid, (*ostate).sgid),
                        );
                        break 'bad;
                    }
                    (*state).gidlist = sudo_user.gid_list;
                    sudo_gidlist_addref((*state).gidlist);

                    if (*state).gidlist != (*ostate).gidlist
                        && sudo_setgroups_v1((*(*state).gidlist).ngids, (*(*state).gidlist).gids)
                            != 0
                    {
                        errstr = b"PERM_FULL_USER: setgroups\0" as *const u8 as *const libc::c_char;
                        break 'bad;
                    }

                    /*if (*state).gidlist != (*ostate).gidlist {
                        if sudo_setgroups_v1((*(*state).gidlist).ngids, (*(*state).gidlist).gids)
                            != 0
                        {
                            errstr =
                                b"PERM_FULL_USER: setgroups\0" as *const u8 as *const libc::c_char;
                            break 'bad;
                        }
                    }*/
                    (*state).ruid = sudo_user.uid;
                    (*state).euid = sudo_user.uid;
                    (*state).suid = sudo_user.uid;
                    sudo_debug_printf!(
                        SUDO_DEBUG_INFO,
                        b"%s: PERM_FULL_USER: uid: \0" as *const u8 as *const libc::c_char,
                        b"[%d, %d, %d] -> [%d, %d, %d]\0" as *const u8 as *const libc::c_char,
                        get_function_name!(),
                        (*ostate).ruid as libc::c_int,
                        (*ostate).euid as libc::c_int,
                        (*ostate).suid as libc::c_int,
                        (*state).ruid as libc::c_int,
                        (*state).euid as libc::c_int,
                        (*state).suid as libc::c_int
                    );
                    if UID_CHANGED!(state, ostate)
                        && setresuid(
                            ID!((*state).ruid, (*ostate).ruid),
                            ID!((*state).euid, (*ostate).euid),
                            ID!((*state).suid, (*ostate).suid),
                        ) != 0
                    {
                        snprintf(
                            errbuf.as_mut_ptr(),
                            ::core::mem::size_of::<[libc::c_char; 1024]>() as libc::c_ulong,
                            b"PERM_FULL_USER: setresuid(%d, %d, %d)\0" as *const u8
                                as *const libc::c_char,
                            ID!((*state).ruid, (*ostate).ruid),
                            ID!((*state).euid, (*ostate).euid),
                            ID!((*state).suid, (*ostate).suid),
                        );
                        break 'bad;
                    }
                }
                PERM_RUNAS => {
                    (*state).rgid = (*ostate).rgid;
                    (*state).egid = if !(sudo_user._runas_gr).is_null() {
                        (*sudo_user._runas_gr).gr_gid
                    } else {
                        (*sudo_user._runas_pw).pw_gid
                    };
                    (*state).sgid = (*ostate).sgid;
                    sudo_debug_printf!(
                        SUDO_DEBUG_INFO,
                        b"%s: PERM_RUNAS: gid: \0" as *const u8 as *const libc::c_char,
                        b"[%d, %d, %d] -> [%d, %d, %d]\0" as *const u8 as *const libc::c_char,
                        get_function_name!(),
                        (*ostate).rgid as libc::c_int,
                        (*ostate).egid as libc::c_int,
                        (*ostate).sgid as libc::c_int,
                        (*state).rgid as libc::c_int,
                        (*state).egid as libc::c_int,
                        (*state).sgid as libc::c_int
                    );
                    if GID_CHANGED!(state, ostate)
                        && setresgid(
                            ID!((*state).rgid, (*ostate).rgid),
                            ID!((*state).egid, (*ostate).egid),
                            ID!((*state).sgid, (*ostate).sgid),
                        ) != 0
                    {
                        errstr =
                            b"unable to change to runas gid\0" as *const u8 as *const libc::c_char;
                        break 'bad;
                    }
                    (*state).gidlist = runas_setgroups();
                    if ((*state).gidlist).is_null() {
                        errstr = b"unable to set runas group vector\0" as *const u8
                            as *const libc::c_char;
                        break 'bad;
                    }
                    (*state).ruid = (*ostate).ruid;
                    (*state).euid = if !(sudo_user._runas_pw).is_null() {
                        (*sudo_user._runas_pw).pw_uid
                    } else {
                        sudo_user.uid
                    };
                    (*state).suid = (*ostate).suid;
                    sudo_debug_printf!(
                        SUDO_DEBUG_INFO,
                        b"%s: PERM_RUNAS: uid: \0" as *const u8 as *const libc::c_char,
                        b"[%d, %d, %d] -> [%d, %d, %d]\0" as *const u8 as *const libc::c_char,
                        get_function_name!(),
                        (*ostate).ruid as libc::c_int,
                        (*ostate).euid as libc::c_int,
                        (*ostate).suid as libc::c_int,
                        (*state).ruid as libc::c_int,
                        (*state).euid as libc::c_int,
                        (*state).suid as libc::c_int
                    );
                    if UID_CHANGED!(state, ostate)
                        && setresuid(
                            ID!((*state).ruid, (*ostate).ruid),
                            ID!((*state).euid, (*ostate).euid),
                            ID!((*state).suid, (*ostate).suid),
                        ) != 0
                    {
                        errstr =
                            b"unable to change to runas uid\0" as *const u8 as *const libc::c_char;
                        break 'bad;
                    }
                }
                PERM_SUDOERS => {
                    (*state).gidlist = (*ostate).gidlist;
                    sudo_gidlist_addref((*state).gidlist);

                    /* assumes euid == ROOT_UID, ruid == user */
                    (*state).rgid = (*ostate).rgid;
                    (*state).egid = sudoers_gid;
                    (*state).sgid = (*ostate).sgid;
                    sudo_debug_printf!(
                        SUDO_DEBUG_INFO,
                        b"%s: PERM_SUDOERS: gid: \0" as *const u8 as *const libc::c_char,
                        b"[%d, %d, %d] -> [%d, %d, %d]\0" as *const u8 as *const libc::c_char,
                        get_function_name!(),
                        (*ostate).rgid as libc::c_int,
                        (*ostate).egid as libc::c_int,
                        (*ostate).sgid as libc::c_int,
                        (*state).rgid as libc::c_int,
                        (*state).egid as libc::c_int,
                        (*state).sgid as libc::c_int
                    );
                    if GID_CHANGED!(state, ostate)
                        && setresgid(
                            ID!((*state).rgid, (*ostate).rgid),
                            ID!((*state).egid, (*ostate).egid),
                            ID!((*state).sgid, (*ostate).sgid),
                        ) != 0
                    {
                        errstr = b"unable to change to sudoers gid\0" as *const u8
                            as *const libc::c_char;
                        break 'bad;
                    }

                    (*state).ruid = ROOT_UID as uid_t;
                    /*
                     * If sudoers_uid == ROOT_UID and sudoers_mode is group readable
                     * we use a non-zero uid in order to avoid NFS lossage.
                     * Using uid 1 is a bit bogus but should work on all OS's.
                     */
                    if sudoers_uid == ROOT_UID as libc::c_uint
                        && sudoers_mode & S_IRGRP!() as libc::c_uint != 0
                    {
                        (*state).euid = 1 as uid_t;
                    } else {
                        (*state).euid = sudoers_uid;
                    }
                    (*state).suid = ROOT_UID as uid_t;
                    sudo_debug_printf!(
                        SUDO_DEBUG_INFO,
                        b"%s: PERM_SUDOERS: uid: \0" as *const u8 as *const libc::c_char,
                        b"[%d, %d, %d] -> [%d, %d, %d]\0" as *const u8 as *const libc::c_char,
                        get_function_name!(),
                        (*ostate).ruid as libc::c_int,
                        (*ostate).euid as libc::c_int,
                        (*ostate).suid as libc::c_int,
                        (*state).ruid as libc::c_int,
                        (*state).euid as libc::c_int,
                        (*state).suid as libc::c_int
                    );
                    if UID_CHANGED!(state, ostate)
                        && setresuid(
                            ID!((*state).ruid, (*ostate).ruid),
                            ID!((*state).euid, (*ostate).euid),
                            ID!((*state).suid, (*ostate).suid),
                        ) != 0
                    {
                        snprintf(
                            errbuf.as_mut_ptr(),
                            ::core::mem::size_of::<[libc::c_char; 1024]>() as libc::c_ulong,
                            b"PERM_FULL_USER: setresuid(%d, %d, %d)\0" as *const u8
                                as *const libc::c_char,
                            ID!((*state).ruid, (*ostate).ruid),
                            ID!((*state).euid, (*ostate).euid),
                            ID!((*state).suid, (*ostate).suid),
                        );
                        break 'bad;
                    }
                }
                PERM_TIMESTAMP => {
                    (*state).gidlist = (*ostate).gidlist;
                    sudo_gidlist_addref((*state).gidlist);
                    (*state).rgid = (*ostate).rgid;
                    (*state).egid = (*ostate).egid;
                    (*state).sgid = (*ostate).sgid;
                    (*state).ruid = ROOT_UID as uid_t;
                    (*state).euid = timestamp_uid;
                    (*state).suid = ROOT_UID as uid_t;
                    sudo_debug_printf!(
                        SUDO_DEBUG_INFO,
                        b"%s: PERM_TIMESTAMP: uid: \0" as *const u8 as *const libc::c_char,
                        b"[%d, %d, %d] -> [%d, %d, %d]\0" as *const u8 as *const libc::c_char,
                        get_function_name!(),
                        (*ostate).ruid as libc::c_int,
                        (*ostate).euid as libc::c_int,
                        (*ostate).suid as libc::c_int,
                        (*state).ruid as libc::c_int,
                        (*state).euid as libc::c_int,
                        (*state).suid as libc::c_int
                    );
                    if UID_CHANGED!(state, ostate)
                        && setresuid(
                            ID!((*state).ruid, (*ostate).ruid),
                            ID!((*state).euid, (*ostate).euid),
                            ID!((*state).suid, (*ostate).suid),
                        ) != 0
                    {
                        snprintf(
                            errbuf.as_mut_ptr(),
                            ::core::mem::size_of::<[libc::c_char; 1024]>() as libc::c_ulong,
                            b"PERM_TIMESTAMP: setresuid(%d, %d, %d)\0" as *const u8
                                as *const libc::c_char,
                            ID!((*state).ruid, (*ostate).ruid),
                            ID!((*state).euid, (*ostate).euid),
                            ID!((*state).suid, (*ostate).suid),
                        );
                        break 'bad;
                    }
                }
                PERM_IOLOG => {
                    (*state).gidlist = (*ostate).gidlist;
                    sudo_gidlist_addref((*state).gidlist);
                    (*state).rgid = (*ostate).rgid;
                    (*state).egid = iolog_gid;
                    (*state).sgid = (*ostate).sgid;
                    (*state).ruid = ROOT_UID as uid_t;
                    (*state).euid = iolog_uid;
                    (*state).suid = ROOT_UID as uid_t;
                    sudo_debug_printf!(
                        SUDO_DEBUG_INFO,
                        b"%s: PERM_IOLOG: gid: \0" as *const u8 as *const libc::c_char,
                        b"[%d, %d, %d] -> [%d, %d, %d]\0" as *const u8 as *const libc::c_char,
                        get_function_name!(),
                        (*ostate).rgid as libc::c_int,
                        (*ostate).egid as libc::c_int,
                        (*ostate).sgid as libc::c_int,
                        (*state).rgid as libc::c_int,
                        (*state).egid as libc::c_int,
                        (*state).sgid as libc::c_int
                    );
                    if GID_CHANGED!(state, ostate)
                        && setresgid(
                            ID!((*state).rgid, (*ostate).rgid),
                            ID!((*state).egid, (*ostate).egid),
                            ID!((*state).sgid, (*ostate).sgid),
                        ) != 0
                    {
                        snprintf(
                            errbuf.as_mut_ptr(),
                            ::core::mem::size_of::<[libc::c_char; 1024]>() as libc::c_ulong,
                            b"PERM_IOLOG: setresgid(%d, %d, %d)\0" as *const u8
                                as *const libc::c_char,
                            ID!((*state).rgid, (*ostate).rgid),
                            ID!((*state).egid, (*ostate).egid),
                            ID!((*state).sgid, (*ostate).sgid),
                        );
                        break 'bad;
                    }
                    sudo_debug_printf!(
                        SUDO_DEBUG_INFO,
                        b"%s: PERM_IOLOG: uid: \0" as *const u8 as *const libc::c_char,
                        b"[%d, %d, %d] -> [%d, %d, %d]\0" as *const u8 as *const libc::c_char,
                        get_function_name!(),
                        (*ostate).ruid as libc::c_int,
                        (*ostate).euid as libc::c_int,
                        (*ostate).suid as libc::c_int,
                        (*state).ruid as libc::c_int,
                        (*state).euid as libc::c_int,
                        (*state).suid as libc::c_int
                    );
                    if UID_CHANGED!(state, ostate)
                        && setresuid(
                            ID!((*state).ruid, (*ostate).ruid),
                            ID!((*state).euid, (*ostate).euid),
                            ID!((*state).suid, (*ostate).suid),
                        ) != 0
                    {
                        snprintf(
                            errbuf.as_mut_ptr(),
                            ::core::mem::size_of::<[libc::c_char; 1024]>() as libc::c_ulong,
                            b"PERM_IOLOG: setresuid(%d, %d, %d)\0" as *const u8
                                as *const libc::c_char,
                            ID!((*state).ruid, (*ostate).ruid),
                            ID!((*state).euid, (*ostate).euid),
                            ID!((*state).suid, (*ostate).suid),
                        );
                        break 'bad;
                    }
                }
                _ => {}
            }
            perm_stack_depth += 1;
            debug_return_bool!(true);
        }

        //bad:
        if *__errno_location() == EAGAIN {
            sudo_warnx!(
                b"%s: %s\0" as *const u8 as *const libc::c_char,
                errstr,
                b"too many processes\0" as *const u8 as *const libc::c_char
            );
        } else {
            sudo_warnx!(b"%s\0" as *const u8 as *const libc::c_char, errstr);
        }
        debug_return_bool!(false);
    } //unsafe
}

#[no_mangle]
pub fn restore_perms() -> bool {
    let mut state: *mut perm_state = std::ptr::null_mut::<perm_state>();
    let mut ostate: *mut perm_state = std::ptr::null_mut::<perm_state>();
    unsafe {
        debug_decl!(SUDOERS_DEBUG_PERMS!());

        if perm_stack_depth < 2 as libc::c_int {
            sudo_warnx!(b"perm stack underflow\0" as *const u8 as *const libc::c_char,);
            debug_return_bool!(true);
        }

        state = &mut *perm_stack
            .as_mut_ptr()
            .offset((perm_stack_depth - 1 as libc::c_int) as isize)
            as *mut perm_state;
        ostate = &mut *perm_stack
            .as_mut_ptr()
            .offset((perm_stack_depth - 2 as libc::c_int) as isize)
            as *mut perm_state;
        perm_stack_depth -= 1;

        sudo_debug_printf!(
            SUDO_DEBUG_INFO,
            b"%s: uid: [%d, %d, %d] -> [%d, %d, %d]\0" as *const u8 as *const libc::c_char,
            get_function_name!(),
            (*state).ruid as libc::c_int,
            (*state).euid as libc::c_int,
            (*state).suid as libc::c_int,
            (*ostate).ruid as libc::c_int,
            (*ostate).euid as libc::c_int,
            (*ostate).suid as libc::c_int
        );
        sudo_debug_printf!(
            SUDO_DEBUG_INFO,
            b"%s: gid: [%d, %d, %d] -> [%d, %d, %d]\0" as *const u8 as *const libc::c_char,
            get_function_name!(),
            (*state).rgid as libc::c_int,
            (*state).egid as libc::c_int,
            (*state).sgid as libc::c_int,
            (*ostate).rgid as libc::c_int,
            (*ostate).egid as libc::c_int,
            (*ostate).sgid as libc::c_int
        );

        /* XXX - more cases here where euid != ruid */
        'bad: loop {
            if OID!((*state).euid, (*ostate).euid) == ROOT_UID as libc::c_uint
                && setresuid(
                    -(1 as libc::c_int) as __uid_t,
                    ROOT_UID as __uid_t,
                    -(1 as libc::c_int) as __uid_t,
                ) != 0
            {
                sudo_warn!(
                    b"setresuid() [%d, %d, %d] -> [%d, %d, %d]\0" as *const u8
                        as *const libc::c_char,
                    (*state).ruid as libc::c_int,
                    (*state).euid as libc::c_int,
                    (*state).suid as libc::c_int,
                    -(1 as libc::c_int),
                    ROOT_UID,
                    -(1 as libc::c_int)
                );
                break 'bad;
            }

            /*if OID!((*state).euid, (*ostate).euid) == ROOT_UID as libc::c_uint {
                if setresuid(
                    -(1 as libc::c_int) as __uid_t,
                    ROOT_UID as __uid_t,
                    -(1 as libc::c_int) as __uid_t,
                ) != 0
                {
                    sudo_warn!(
                        b"setresuid() [%d, %d, %d] -> [%d, %d, %d]\0" as *const u8
                            as *const libc::c_char,
                        (*state).ruid as libc::c_int,
                        (*state).euid as libc::c_int,
                        (*state).suid as libc::c_int,
                        -(1 as libc::c_int),
                        ROOT_UID,
                        -(1 as libc::c_int)
                    );
                    break 'bad;
                }
            }*/
            if setresgid(
                OID!((*state).rgid, (*ostate).rgid),
                OID!((*state).egid, (*ostate).egid),
                OID!((*state).sgid, (*ostate).sgid),
            ) != 0
            {
                sudo_warn!(
                    b"setresgid() [%d, %d, %d] -> [%d, %d, %d]\0" as *const u8
                        as *const libc::c_char,
                    (*state).rgid as libc::c_int,
                    (*state).egid as libc::c_int,
                    (*state).sgid as libc::c_int,
                    OID!((*state).rgid, (*ostate).rgid),
                    OID!((*state).egid, (*ostate).egid),
                    OID!((*state).sgid, (*ostate).sgid)
                );
                break 'bad;
            }
            /*if (*state).gidlist != (*ostate).gidlist {
                if sudo_setgroups_v1((*(*ostate).gidlist).ngids, (*(*ostate).gidlist).gids) != 0 {
                    sudo_warn!(b"setgroups()\0" as *const u8 as *const libc::c_char,);
                    break 'bad;
                }
            }*/
            if (*state).gidlist != (*ostate).gidlist
                && sudo_setgroups_v1((*(*ostate).gidlist).ngids, (*(*ostate).gidlist).gids) != 0
            {
                sudo_warn!(b"setgroups()\0" as *const u8 as *const libc::c_char,);
                break 'bad;
            }

            if setresuid(
                OID!((*state).ruid, (*ostate).ruid),
                OID!((*state).euid, (*ostate).euid),
                OID!((*state).suid, (*ostate).suid),
            ) != 0
            {
                sudo_warn!(
                    b"setresuid() [%d, %d, %d] -> [%d, %d, %d]\0" as *const u8
                        as *const libc::c_char,
                    (*state).ruid as libc::c_int,
                    (*state).euid as libc::c_int,
                    (*state).suid as libc::c_int,
                    OID!((*state).ruid, (*ostate).ruid),
                    OID!((*state).euid, (*ostate).euid),
                    OID!((*state).suid, (*ostate).suid)
                );
                break 'bad;
            }
            sudo_gidlist_delref((*state).gidlist);
            debug_return_bool!(true);
        }

        //bad
        debug_return_bool!(false);
    } //unsafe
}

fn runas_setgroups() -> *mut gid_list {
    let mut gidlist: *mut gid_list = std::ptr::null_mut::<gid_list>();
    unsafe {
        debug_decl!(SUDOERS_DEBUG_PERMS!());

        gidlist = runas_getgroups();
        /*if !gidlist.is_null() && def_preserve_groups!() == 0 {
            if sudo_setgroups_v1((*gidlist).ngids, (*gidlist).gids) < 0 as libc::c_int {
                sudo_gidlist_delref(gidlist);
                gidlist = std::ptr::null_mut::<gid_list>();
            }
        }*/
        if !gidlist.is_null()
            && def_preserve_groups!() == 0
            && sudo_setgroups_v1((*gidlist).ngids, (*gidlist).gids) < 0 as libc::c_int
        {
            sudo_gidlist_delref(gidlist);
            gidlist = std::ptr::null_mut::<gid_list>();
        }

        debug_return_ptr!(gidlist);
    } //unsafe
}
